package top.codef.persist.descriptors;

import java.math.BigDecimal;
import java.math.BigInteger;

import javax.money.MonetaryAmount;
import javax.money.NumberValue;

import org.hibernate.type.descriptor.WrapperOptions;
import org.hibernate.type.descriptor.java.AbstractJavaType;

import top.codef.money.interfaces.MercuryMonetaryAmountFormat;
import top.codef.properties.MercuryPersistProperties;

public class MonetaryTypeDescriptor<T extends MonetaryAmount> extends AbstractJavaType<T> {

	private static final long serialVersionUID = 7603443740553725933L;

	protected final MercuryPersistProperties mercuryPersistProperties;

	protected final MercuryMonetaryAmountFormat mercuryMonetaryAmountFormat;

	public MonetaryTypeDescriptor(Class<T> type, MercuryPersistProperties mercuryPersistProperties,
			MercuryMonetaryAmountFormat mercuryMonetaryAmountFormat) {
		super(type);
		this.mercuryPersistProperties = mercuryPersistProperties;
		this.mercuryMonetaryAmountFormat = mercuryMonetaryAmountFormat;
	}

	@Override
	@SuppressWarnings("unchecked")
	public <X> X unwrap(T value, Class<X> type, WrapperOptions options) {
//		System.out.println(value);
		NumberValue numberValue = mercuryPersistProperties.isPersistOnMultiply100() ? value.multiply(100).getNumber()
				: value.getNumber();
		if (Long.class.equals(type))
			return (X) Long.valueOf(numberValue.longValue());
		else if (BigInteger.class.equals(type))
			return (X) BigInteger.valueOf(numberValue.longValue());
		else if (BigDecimal.class.equals(type))
			return (X) BigDecimal.valueOf(numberValue.doubleValue());
		else if (String.class.equals(type))
			return (X) numberValue.toString();
		throw unknownUnwrap(type);
	}

	@Override
	@SuppressWarnings("unchecked")
	public <X> T wrap(X value, WrapperOptions options) {
		String strValue = value.toString();
		if (MonetaryAmount.class.isAssignableFrom(value.getClass()))
			return mercuryMonetaryAmountFormat.parse(strValue, getJavaTypeClass());
		T money = mercuryMonetaryAmountFormat.parse(strValue, getJavaTypeClass());
		if (mercuryPersistProperties.isPersistOnMultiply100())
			money = (T) money.divide(100);
		return money;
	}

}
